package com.zt.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zt.dto.TeacherRatingRequest;
import com.zt.dto.TeacherRankingDTO;
import com.zt.entity.Result;
import com.zt.mapper.TeacherRatingMapper;
import com.zt.pojo.Bookings;
import com.zt.pojo.Courses;
import com.zt.pojo.TeacherRating;
import com.zt.pojo.Teachers;
import com.zt.pojo.Users;
import com.zt.service.BookingsService;
import com.zt.service.CoursesService;
import com.zt.service.TeacherRatingService;
import com.zt.service.TeachersService;
import com.zt.service.UsersService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author system
 * @description 针对表【teacher_rating(教师评价表)】的数据库操作Service实现
 */
@Service
@Slf4j
public class TeacherRatingServiceImpl extends ServiceImpl<TeacherRatingMapper, TeacherRating>
    implements TeacherRatingService {

    // Redis缓存相关常量
    private static final String TEACHER_RANKING_KEY = "teacher:ranking:";
    private static final Long RANKING_CACHE_TTL = 30L; // 缓存30分钟

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private BookingsService bookingsService;
    
    @Autowired
    private CoursesService coursesService;
    
    @Autowired
    private TeachersService teachersService;
    
    @Autowired
    private UsersService usersService;

    @Override
    public Result submitRating(TeacherRatingRequest ratingRequest) {
        try {
            log.info("开始提交教师评价，参数：{}", ratingRequest);
            
            // 1. 参数校验
            if (ratingRequest == null) {
                return Result.error("评价请求不能为空");
            }
            
            Integer bookingId = ratingRequest.getBookingId();
            Integer userId = ratingRequest.getUserId();
            Integer rating = ratingRequest.getRating();
            String comment = ratingRequest.getComment();
            
            if (bookingId == null) {
                return Result.error("预约ID不能为空");
            }
            if (userId == null) {
                return Result.error("用户ID不能为空");
            }
            if (rating == null || rating < 1 || rating > 5) {
                return Result.error("评分必须在1-5分之间");
            }
            if (StrUtil.isBlank(comment)) {
                return Result.error("评价内容不能为空");
            }
            if (comment.length() > 500) {
                return Result.error("评价内容不能超过500字");
            }
            
            // 2. 查询预约信息
            Bookings booking = bookingsService.getById(bookingId);
            if (booking == null) {
                return Result.error("预约记录不存在");
            }
            
            // 3. 验证用户权限（确保是预约的用户本人）
            if (!userId.equals(booking.getUserId())) {
                return Result.error("无权限评价此预约");
            }
            
            // 4. 查询课程信息获取教师ID
            Courses course = coursesService.getById(booking.getCourseId());
            if (course == null) {
                return Result.error("课程信息不存在");
            }
            
            Integer teacherId = course.getTeacherId();
            if (teacherId == null) {
                return Result.error("教师信息不存在");
            }
            
            // 5. 检查是否已经评价过
            LambdaQueryWrapper<TeacherRating> existWrapper = new LambdaQueryWrapper<>();
            existWrapper.eq(TeacherRating::getUserId, userId)
                        .eq(TeacherRating::getTeacherId, teacherId)
                        .eq(TeacherRating::getBookingId, bookingId);

            TeacherRating existingRating = this.getOne(existWrapper);
            if (existingRating != null) {
                // 如果已存在评价，则更新
                existingRating.setComment(comment);
                existingRating.setCommentRating(rating.floatValue());
                existingRating.setUpdateAt(new Date());
                
                boolean updateResult = this.updateById(existingRating);
                if (!updateResult) {
                    return Result.error("更新评价失败");
                }
                
                log.info("更新教师评价成功，用户ID：{}，教师ID：{}，评分：{}", userId, teacherId, rating);
            } else {
                // 创建新的评价记录
                TeacherRating teacherRating = new TeacherRating();
                teacherRating.setBookingId(bookingId);
                teacherRating.setUserId(userId);
                teacherRating.setTeacherId(teacherId);
                teacherRating.setComment(comment);
                teacherRating.setCommentRating(rating.floatValue());
                teacherRating.setCreateAt(new Date());
                teacherRating.setUpdateAt(new Date());

                boolean saveResult = this.save(teacherRating);
                if (!saveResult) {
                    return Result.error("提交评价失败");
                }

                log.info("提交教师评价成功，用户ID：{}，教师ID：{}，评分：{}", userId, teacherId, rating);
            }

            // 清除排行榜缓存，因为评价数据已更新
            clearRankingCache();
            
            // 6. 构建返回数据
            Map<String, Object> resultData = new HashMap<>();
            resultData.put("bookingId", bookingId);
            resultData.put("userId", userId);
            resultData.put("teacherId", teacherId);
            resultData.put("rating", rating);
            resultData.put("comment", comment);
            resultData.put("submitTime", new Date());

            // 默认刷新排行榜
            getTeacherRanking(10);
            
            return Result.success("评价提交成功", resultData);
            
        } catch (Exception e) {
            log.error("提交教师评价异常：", e);
            return Result.error("提交评价发生异常：" + e.getMessage());
        }
    }

    @Override
    public Result getTeacherRanking(Integer limit) {
        try {
            log.info("开始获取教师排行榜，限制数量：{}", limit);

            // 设置默认限制数量
            if (limit == null || limit <= 0) {
                limit = 10;
            }
            if (limit > 100) {
                limit = 100; // 最多返回100条记录
            }

            // 1. 先从Redis缓存中获取排行榜数据
            String cacheKey = TEACHER_RANKING_KEY + "all";
            List<TeacherRankingDTO> cachedRanking = getCachedRanking(cacheKey);

            if (cachedRanking != null && !cachedRanking.isEmpty()) {
                log.info("从Redis缓存获取排行榜数据，总数：{}", cachedRanking.size());

                // 根据limit截取数据并重新设置排名
                List<TeacherRankingDTO> limitedRanking = cachedRanking.stream()
                        .limit(limit)
                        .collect(Collectors.toList());

                for (int i = 0; i < limitedRanking.size(); i++) {
                    limitedRanking.get(i).setRank(i + 1);
                }

                return Result.success("获取排行榜成功（缓存）", limitedRanking);
            }

            log.info("缓存中无数据，开始从数据库计算排行榜");

            // 1. 获取所有教师的评价统计数据
            List<TeacherRating> allRatings = this.list();

            if (allRatings.isEmpty()) {
                return Result.success("获取排行榜成功", new ArrayList<>());
            }

            // 2. 按教师ID分组统计评价数据
            Map<Integer, List<TeacherRating>> ratingsByTeacher = allRatings.stream()
                    .collect(Collectors.groupingBy(TeacherRating::getTeacherId));

            // 3. 计算每个教师的统计数据
            List<TeacherRankingDTO> rankingList = new ArrayList<>();

            for (Map.Entry<Integer, List<TeacherRating>> entry : ratingsByTeacher.entrySet()) {
                Integer teacherId = entry.getKey();
                List<TeacherRating> teacherRatings = entry.getValue();

                // 查询教师信息
                Teachers teacher = teachersService.getById(teacherId);
                if (teacher == null || teacher.getStatus() != 1) {
                    continue; // 跳过不存在或未激活的教师
                }

                // 查询教师用户信息
                Users teacherUser = usersService.getById(teacher.getUserId());
                if (teacherUser == null) {
                    continue;
                }

                // 计算平均评分
                double avgRating = teacherRatings.stream()
                        .mapToDouble(TeacherRating::getCommentRating)
                        .average()
                        .orElse(0.0);

                // 统计总授课次数（通过课程表查询）
                LambdaQueryWrapper<Courses> courseWrapper = new LambdaQueryWrapper<>();
                courseWrapper.eq(Courses::getTeacherId, teacherId);
                int totalCourses = (int) coursesService.count(courseWrapper);

                // 构建排行榜DTO
                TeacherRankingDTO rankingDTO = new TeacherRankingDTO();
                rankingDTO.setTeacherId(teacherId);
                rankingDTO.setTeacherName(teacher.getName() != null ? teacher.getName() : teacherUser.getNickname());
                rankingDTO.setAvatarUrl(teacherUser.getAvatarUrl() != null ? teacherUser.getAvatarUrl() :
                    "https://api.dicebear.com/7.x/micah/svg?seed=" + teacherId);
                rankingDTO.setAverageRating(BigDecimal.valueOf(avgRating).setScale(2, RoundingMode.HALF_UP));
                rankingDTO.setTotalRatings(teacherRatings.size());
                rankingDTO.setSubjects(teacher.getSubjectIds() != null ? teacher.getSubjectIds() : "");
                rankingDTO.setTeachingAge(teacher.getTeachingAge() != null ? teacher.getTeachingAge() : 0);
                rankingDTO.setTotalCourses(totalCourses);
                rankingDTO.setCertificationStatus(teacher.getCertificationStatus() != null ? teacher.getCertificationStatus() : 0);

                rankingList.add(rankingDTO);
            }

            // 4. 按平均评分降序排序，评分相同时按评价数量降序排序
            rankingList.sort((a, b) -> {
                int ratingCompare = b.getAverageRating().compareTo(a.getAverageRating());
                if (ratingCompare == 0) {
                    return b.getTotalRatings().compareTo(a.getTotalRatings());
                }
                return ratingCompare;
            });

            // 5. 将完整排行榜存储到Redis缓存
            if (!rankingList.isEmpty()) {
                // 设置完整排名
                for (int i = 0; i < rankingList.size(); i++) {
                    rankingList.get(i).setRank(i + 1);
                }

                // 存储到Redis
                cacheRanking(cacheKey, rankingList);
                log.info("排行榜数据已存储到Redis缓存，总数：{}", rankingList.size());
            }

            // 6. 限制返回数量
            List<TeacherRankingDTO> finalRanking = rankingList.stream()
                    .limit(limit)
                    .collect(Collectors.toList());

            // 重新设置排名（因为可能被limit截取）
            for (int i = 0; i < finalRanking.size(); i++) {
                finalRanking.get(i).setRank(i + 1);
            }

            log.info("获取教师排行榜成功，返回{}条记录", finalRanking.size());
            return Result.success("获取排行榜成功", finalRanking);

        } catch (Exception e) {
            log.error("获取教师排行榜异常：", e);
            return Result.error("获取排行榜发生异常：" + e.getMessage());
        }
    }

    /**
     * 从Redis缓存获取排行榜数据
     */
    @SuppressWarnings("unchecked")
    private List<TeacherRankingDTO> getCachedRanking(String cacheKey) {
        try {
            Object cachedData = redisTemplate.opsForValue().get(cacheKey);
            if (cachedData instanceof List) {
                return (List<TeacherRankingDTO>) cachedData;
            }
        } catch (Exception e) {
            log.warn("从Redis获取排行榜缓存失败：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 将排行榜数据存储到Redis缓存
     */
    private void cacheRanking(String cacheKey, List<TeacherRankingDTO> rankingList) {
        try {
            redisTemplate.opsForValue().set(cacheKey, rankingList, RANKING_CACHE_TTL, TimeUnit.MINUTES);
            log.info("排行榜数据已缓存到Redis，key：{}，过期时间：{}分钟", cacheKey, RANKING_CACHE_TTL);
        } catch (Exception e) {
            log.warn("存储排行榜到Redis缓存失败：{}", e.getMessage());
        }
    }

    /**
     * 清除排行榜缓存（在有新评价时调用）
     */
    public void clearRankingCache() {
        try {
            String pattern = TEACHER_RANKING_KEY + "*";
            Set<String> keys = redisTemplate.keys(pattern);
            if (keys != null && !keys.isEmpty()) {
                redisTemplate.delete(keys);
                log.info("已清除排行榜缓存，清除key数量：{}", keys.size());
            }
        } catch (Exception e) {
            log.warn("清除排行榜缓存失败：{}", e.getMessage());
        }
    }
}
